package com.gitee.l0km.javadocreader;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.MemberDoc;
import com.sun.javadoc.Parameter;

@SuppressWarnings("restriction")
public class MemberMatchUtils {

	/**
	 * 返回类型的全名字符串
	 * @param type
	 */
	private static String getTypeName(Class<?> type) {
		StringBuilder dimensions = new StringBuilder();
		while (type.isArray()) {
			dimensions.append("[]");
			type = type.getComponentType();
		} 
		String name = type.getName().replaceAll("\\$", "\\.");
		return new StringBuilder(name).append(dimensions).toString();
	}
	/**
	 * 如果两个类型字符串匹配，返回{@code true}，否则返回{@code false}
	 * @param docType
	 * @param type
	 */
	private static boolean equalType(com.sun.javadoc.Type docType,Class<?> type) {
		String typeName = getTypeName(type);
		String paramName = docType.qualifiedTypeName()+docType.dimension();
		if(typeName.equals(paramName)) {
			return true;
		}
		/** 
		 * primitive为true,说明docType 代表的类型没有对应的源码注释，
		 * 这时qualifiedTypeName()返回只是该类型的类名(不包含包名) ,
		 * 所以尝试使用Class的simpleName来比较
		 */
		return (docType.isPrimitive() && docType.qualifiedTypeName().equals(((Class<?>)type).getSimpleName()));
	}
	/**
	 * 检查两个方法对象的签名是否匹配<br>
	 * @param member
	 * @param doc
	 * @return 不匹配返回 {@code false} ,匹配返回 {@code true}
	 */
	private static boolean match(Member member, MemberDoc doc) {
		if (!member.getName().equals(doc.name())){
			return false;
		}
		if(member instanceof Field) {
			return true;
		}
		Class<?>[] paramTypes;
		if(member instanceof Method){
			paramTypes = ((Method)member).getParameterTypes();
		}else if(member instanceof Constructor<?>){
			paramTypes = ((Constructor<?>)member).getParameterTypes();
		}else{
			throw new IllegalArgumentException(String.format("INVALID member type %s,Method or Constructor required",member.getClass().getSimpleName()));
		}
		if(!(doc instanceof ExecutableMemberDoc)) {
			throw new IllegalArgumentException(String.format("INVALID doc type %s,ExecutableMemberDoc required",doc.getClass().getSimpleName()));
		}
		Parameter[] parameters = ((ExecutableMemberDoc)doc).parameters();
		if (paramTypes.length != parameters.length) {
			return false;
		}
		for (int i = 0; i < paramTypes.length; ++i) {
			if(!equalType(parameters[i].type(),paramTypes[i])) {
				return false;
			}
		}
		return true;
	}
	/**
	 * 在{@link ClassDoc}中查找与 {@link Member} 匹配的{@link MemberDoc}对象<br>
	 * 没找到匹配的对象则返回{@code null}
	 * @param classDoc
	 * @param member 
	 */
	public static MemberDoc findMember(ClassDoc classDoc,Member member) {
		if (null == classDoc || null == member){
			return null;
		}
		if(!equalType(classDoc,member.getDeclaringClass())) {
			return null;
		}
		MemberDoc[] memberDocs;
		if(member instanceof Field) {
			memberDocs = classDoc.fields();
		}else if(member instanceof Method){
			memberDocs = classDoc.methods();
		}else if(member instanceof Constructor<?>){
			memberDocs = classDoc.constructors();
		}else{
			throw new IllegalArgumentException(String.format("INVALID member type %s,Field,Method or Constructor required",member.getClass().getSimpleName()));
		}
		for (int i = 0 ; i < memberDocs.length ; ++ i ) {
			if (match(member, memberDocs[i]))
				return memberDocs[i];
		}
		return null;
	}
}
